// graphdata.cpp: implementation of the graphdata class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "waveeditor.h"
#include "graphdata.h"
#include "languagecomponents.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#include <new>

_signalsline::_signalsline() : sig(NULL), signalsnumber(0)
{
}

_signalsline::~_signalsline()
{
	if( sig != NULL )
	{
		delete[] sig;
		sig = NULL;
	}
}

void  _signalsline::ReallocateSignalsNumber(ULONG asignalsnumber)
{
    delete[] sig;
    sig = NULL;

    signalsnumber = asignalsnumber;
    if (signalsnumber)
    {
        sig = new BYTE[signalsnumber];
        memset(&sig[0], 0, sizeof(BYTE) * signalsnumber);
    }
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

graphdata::graphdata()
{
    signal_start_pos = NULL;
	lastbitcoordinatesx = NULL;
	lastbitcoordinatesy = NULL;
	RuleBordersForSignal = NULL;
	LastAbsoluteValue = NULL;

	ClearSignalsLine(&tempsignal);
	yoffset			=	4;
	deltax			=	1;
	deltay			=	20;
	pagelength		=	16000;
	TimeType = "ms";
	NumberOfSignals = 0;
}

graphdata::~graphdata()
{
	RemoveAll();
}

void graphdata::RemoveAll()
{
	NumberOfSignals = 0;
	linename	.RemoveAll();
	linepos		.RemoveAll();
	signals_status		.RemoveAll();
	signals_cut_x		.RemoveAll();
	signalsname	.RemoveAll();
	ClearSignalsLine(&tempsignal);
	ClearSignalsLine(&tempflags);

	delete[] RuleBordersForSignal;
	delete[] LastAbsoluteValue;
    delete[] signal_start_pos;
    delete[] lastbitcoordinatesx;
    delete[] lastbitcoordinatesy;
    signal_start_pos = NULL;
    lastbitcoordinatesx = NULL;
    lastbitcoordinatesy = NULL;
	RuleBordersForSignal = NULL;
	LastAbsoluteValue = NULL;

    //last_signal_status.ReallocateSignalsNumber(0);
    //lastbitstatus.ReallocateSignalsNumber(0);
}


void graphdata::PutBitInSignal(BYTE bit, WORD place)
{
	tempsignal.sig[place]	=	bit;
}



BYTE graphdata::GetBitInSignal( WORD PositionInGraph, DWORD NumberOfSignal )
{
	if ( PositionInGraph >= (DWORD) signals_status.GetSize() )
	{
		return 2;
	}
	return signals_status[PositionInGraph].sig[NumberOfSignal];
}

void graphdata::AddSignal()
{
	AddFlagsToSignals();
//	signals_status.Add(tempsignal);
	ClearSignalsLine(&tempsignal);
	ClearSignalsLine(&tempflags);
}

void graphdata::AddSignalsName(ScenarioSignals *signalsnme)
{
	for(int i=0;i<signalsnme->GetNumberOfSignals();i++)
	{
//		if(signalsnme->CheckIfSignalWasUsed(i) == TRUE)
//		{
			signalsname.Add(signalsnme->GetSignalName(i));
//		}
	}
}


void graphdata::AddLine(CString name, DWORD offset)
{
	linepos	.Add(offset);
	linename.Add(name);
}

DWORD graphdata::GetNumberOfSignals()
{
	return signals_status.GetSize();
}

DWORD graphdata::GetNumberOfLines()
{
	return linepos.GetSize();
}

DWORD graphdata::GetNumberOfSignalsName()
{
	return signalsname.GetSize();
}

CArray<RuleBorders, RuleBorders> * graphdata::GetRuleBordersForSignal( int SignalNumber )
{
	if ( SignalNumber < NumberOfSignals )
	{
		return &(RuleBordersForSignal[SignalNumber]);
	}
	else
	{
		return NULL;
	}
}

void graphdata::SetTotalSize( __int64 NewTotalSize )
{
	TotalSize = NewTotalSize;
}

__int64 graphdata::GetTotalSize()
{
	return TotalSize;
}

__int64 graphdata::GetSizeInPixels( __int64 Size )
{
	return __int64( double(Size) / pagelength * windowdelta );
}

int graphdata::GetPreciseVerticalSizeOfSignal()
{
	return deltay - 2*yoffset;
}

CString graphdata::GetLineName(DWORD pos)
{
	if(pos>=(DWORD)linename.GetSize())
	{
		return "";
	}
	return linename[pos];
}


DWORD graphdata::GetLineOffset(DWORD pos)
{
	if(pos>=(DWORD)linepos.GetSize())
	{
		return 0;
	}
	return linepos[pos];
}

/*void graphdata::SetTimeType( CString NewTimeType )
{
	TimeType = NewTimeType;
}*/

CString graphdata::GetSignalName(DWORD pos)
{
	if(pos>=(DWORD)signalsname.GetSize())
	{
		return "";
	}
	return signalsname[pos];

}

void graphdata::newsignal()
{
	ClearSignalsLine(&tempsignal);
}


void graphdata::SetDeltay(unsigned int cy)
{
	deltay	=	cy;
}

unsigned int graphdata::GetDeltay()
{
	return deltay;
}

void graphdata::SetSignalBar(WORD signalnumber, CPoint p)
{
	if(signalnumber >= signalsname.GetSize())
	{
		return;
	}
	lastbitcoordinatesx	[signalnumber]	=	p.x;
	lastbitcoordinatesy	[signalnumber]	=	p.y;
	lastbitstatus.sig	[signalnumber]	=	GetBitInSignal( 0, signalnumber )%10;
	if((lastbitstatus.sig[signalnumber]%10)	==	0)
	{
		lastbitcoordinatesy[signalnumber] += (deltay-yoffset);
	}
	else
	{
		lastbitcoordinatesy[signalnumber] += yoffset;
	}
}


/*  old version
int graphdata::GetPolyLineArrayForSignal(WORD signalpos, BYTE signalnumber, CPoint *p)
{
	xcoor tempx;
	if((unsigned int)signals_status.GetSize() <= signalpos)
	{
		return -1;
	}
	BYTE	currentbit	=	GetBitInSignal(signalnumber,signalpos);
	if(currentbit	>=	10)
	{
		tempx							=			lastbitcoordinatesx[signalnumber];
		p[0].x	=	p[4].x	=	p[3].x	=	(int)	lastbitcoordinatesx[signalnumber];
		p[0].y	=	p[4].y	=	p[1].y	=			deltay*(lastbitcoordinatesy[signalnumber]/deltay)
													+yoffset;
		p[1].x	=	p[2].x				=	(int)	(tempx+deltax);
		p[2].y	=	p[3].y				=	(int)	p[0].y+deltay-yoffset-yoffset;
		lastbitstatus.sig	[signalnumber]	=	currentbit%10;
		if((currentbit % 10) ==	1)
		{
			lastbitcoordinatesy	[signalnumber]	=	p[1].y;
			lastbitcoordinatesx	[signalnumber]	=	tempx+deltax;
		}
		else
		{
			lastbitcoordinatesy	[signalnumber]	=	p[2].y;
			lastbitcoordinatesx	[signalnumber]	=	tempx+deltax;
		}
		return	5;
	}
	
	
	if(currentbit	==	lastbitstatus.sig[signalnumber])
	{
		tempx											=			lastbitcoordinatesx[signalnumber];
		p[0].x								=	p[1].x	=	(int)	lastbitcoordinatesx[signalnumber];
		p[0].y								=	p[1].y	=			lastbitcoordinatesy[signalnumber];
		p[1].x											=	(int)	(tempx+deltax);
		lastbitcoordinatesy	[signalnumber]				=			p[1].y;
		lastbitcoordinatesx	[signalnumber]				=			tempx+deltax;
		lastbitstatus.sig	[signalnumber]				=			currentbit;
		return 2;
	}
	else
	{
		tempx											=			lastbitcoordinatesx[signalnumber];
		if(currentbit	!=	0)
		{
			p[0].y	=	p[1].y	=			lastbitcoordinatesy[signalnumber];
			p[0].x	=	p[1].x	=	(int)	lastbitcoordinatesx[signalnumber];
			p[1].y				+=			yoffset-deltay+yoffset;
		}
		else
		{
			p[0].y	=	p[1].y	=			lastbitcoordinatesy[signalnumber];
			p[0].x	=	p[1].x	=	(int)	lastbitcoordinatesx[signalnumber];
			p[1].y				+=			-yoffset+deltay-yoffset;
		}
		p[2]								=			p[1];
		p[2].x								=	(int)	(tempx+deltax);
		lastbitcoordinatesy[signalnumber]	=			p[2].y;
		lastbitcoordinatesx[signalnumber]	=			tempx+deltax;
		lastbitstatus.sig	[signalnumber]	=			currentbit;
		return 3;
	}
}
*/


int graphdata::GetPolyLineArrayForSignal(WORD signalpos, WORD signalnumber, CPoint *p)
{
	xcoor tempx;
	_1stmark.optimize	=	FALSE;
	_2ndmark.optimize	=	FALSE;
	if((unsigned int)signals_status.GetSize() <= signalpos)
	{
		return -1;
	}
	BYTE	currentbyte	=	GetBitInSignal( signalpos, signalnumber );
	BYTE	currentbit	=	currentbyte%10;
	if(currentbyte	>=	20)
	{
		tempx							=			lastbitcoordinatesx[signalnumber];
		p[0].x	=	p[4].x	=	p[3].x	=	(int)	lastbitcoordinatesx[signalnumber];
		/*p[0].y	=	p[4].y	=	p[1].y	=			deltay*(lastbitcoordinatesy[signalnumber]/deltay)
													+yoffset;*/
		p[0].y = p[4].y	= p[1].y = lastbitcoordinatesy[signalnumber] + ( deltay - 2*yoffset )*( lastbitstatus.sig[signalnumber] - 1 );
		p[1].x	=	p[2].x				=	(int)	(tempx+deltax);
		p[2].y	=	p[3].y				=	(int)	p[0].y+deltay-yoffset-yoffset;
		lastbitstatus.sig	[signalnumber]	=	currentbit;
		if(currentbit  ==	1)
		{
			lastbitcoordinatesy	[signalnumber]	=	p[1].y;
			lastbitcoordinatesx	[signalnumber]	=	tempx+deltax;
		}
		else
		{
			lastbitcoordinatesy	[signalnumber]	=	p[2].y;
			lastbitcoordinatesx	[signalnumber]	=	tempx+deltax;
		}
		return	5;
	}
	
	
	if(currentbit	==	lastbitstatus.sig[signalnumber])
	{
		p[0].x								=	p[1].x	=			lastbitcoordinatesx[signalnumber];
		p[0].y								=	p[1].y	=			lastbitcoordinatesy[signalnumber];
		p[1].x											+=			deltax;
		lastbitcoordinatesy	[signalnumber]				=			p[1].y;
		lastbitcoordinatesx	[signalnumber]				+=			deltax;
		lastbitstatus.sig	[signalnumber]				=			currentbit;
		return 2;
	}
	else
	{
		if(currentbit	==	1)
		{
			p[0].y	=	p[1].y	=			lastbitcoordinatesy[signalnumber];
			p[0].x	=	p[1].x	=			lastbitcoordinatesx[signalnumber];
			p[1].y				+=			yoffset-deltay+yoffset;
		}
		else
		{
			p[0].y	=	p[1].y	=			lastbitcoordinatesy[signalnumber];
			p[0].x	=	p[1].x	=			lastbitcoordinatesx[signalnumber];
			p[1].y				+=			-yoffset+deltay-yoffset;
		}
		p[2]								=			p[1];
		p[2].x								+=			deltax;
		lastbitcoordinatesy[signalnumber]	=			p[2].y;
		lastbitcoordinatesx[signalnumber]	+=			deltax;
		lastbitstatus.sig	[signalnumber]	=			currentbit;
		return 3;
	}
}



__int64 graphdata::GetPageLength()
{
	return pagelength;
}



void graphdata::SetDeltax(xcoor x)
{
	deltax	=	x;
}



void graphdata::ClearSignalsLine(_signalsline *sig)
{
	for(int i=0;i<sig->signalsnumber;i++)
	{
		sig->sig[i]	=	0;
	}
}


BOOL graphdata::CompareBitWithSignalBit(WORD signalnumber,BYTE bit)
{
	if(signals_status.GetSize()<1)
	{
		return TRUE;
	}
	if(signals_status[signals_status.GetSize()-1].sig[signalnumber]	==	bit)
	{
		return TRUE;
	}
	return FALSE;
}



void graphdata::SetChangedFlagInSignal(WORD signalnumber)
{
	if(signals_status.GetSize()<1)
	{
		return ;
	}
	tempsignal.sig[signalnumber]	+=	10;
	
}

BOOL graphdata::GetChangedFlagInSignal(WORD signalpos, WORD signalnumber)
{
	if(signals_status[signalpos].sig[signalnumber] >= 10)
	{
		return TRUE;
	}
	return FALSE;
}



/*BOOL graphdata::CompareWithLastSignal()
{
	if(signals_status.GetSize() <1)
	{
		return TRUE;
	}
	for(int i=0;i<32;i++)
	{
		//checking if signal change status first time from 1/0 to 0/1 after adding signal to graph 
		if( (tempflags.sig[i]	== 0)&&
			(tempsignal.sig[i]	!= ( (signals_status[signals_status.GetSize()-1].sig[i]) % 10 ) ))
		{
			tempflags.sig[i]	=	10+tempsignal.sig[i];	
		}
		else
		{
			//checking if signal added changes after first change == too many changes
			if( (tempflags.sig[i]	>= 10)&&(tempflags.sig[i]	<= 20)&&
				(tempsignal.sig[i]	!= ( tempflags.sig[i] % 10 ) ))
			{
				tempflags.sig[i]	=	20;	
			}
		}
	}
	return TRUE;
}*/



void graphdata::AddFlagsToSignals()
{
	for(int i=0;i<32;i++)
	{
		if(tempflags.sig[i] >= 20)//can not show signal - too many changes
		{
			tempsignal.sig[i]	+=	10;
		}
	}

}

void graphdata::SetPageLength(__int64 plength)
{
	pagelength	=	plength;
}

CString graphdata::GetStretchClkFormat()
{
	int			x	=	(int) deltax;
	char number[12];
	_itoa(x,number,10);
	CString num		=	number;
	CString result	=	"1:"+num+" (pixel)";
	return result;

}


void graphdata::SetOffset(__int64 _offset)
{
	globaloffset	=	_offset;
}

/*int graphdata::GetPolyLineArrayForClock(int x, int y, WORD numofsignal, CPoint *p)
{
	p[0].x				=	(int)	(numofsignal*deltax);
	p[1].x	=	p[2].x	=	(int)	((numofsignal+1)*deltax);
	if((numofsignal % 2) == 0)
	{
		p[0].y	=	p[1].y	=	y;
		p[2].y	=	p[0].y	+	deltay;
	}
	else
	{
		p[0].y	=	p[1].y	=	y+deltay;
		p[2].y	=	p[0].y	-	deltay;
	
	}
	return 3;
}*/

xcoor graphdata::GetDeltax() const
{
	return deltax;
}

void graphdata::SetGroupName(CString name)
{
	groupname	=	name;
}

CString graphdata::GetGroupName()
{
	return groupname;
}

CString graphdata::GetTrueCoordinates(CPoint point)
{
	__int64 TrueCoord = GetTrueCoordinates( point.x );
	CString number	= ( TrueCoord != -1 ) ? Long64ToCString( TrueCoord ) : " error";
	return (number + " : " + TimeType);
}

__int64 graphdata::GetTrueCoordinates( long coordX )
{
	DWORD x	=	coordX/windowratio;
	return ((x > graphdelta) || ( deltax == 0 ) ) ? -1 : signals_cut_x[x]; 
}

__int64 graphdata::GetNearestRealCoordinates( long x )
{
	long	res	=	x/long(windowratio);
	if(deltax == 0)
	{
		return 0;
	}
	if(res > (long)graphdelta)
	{
		return signals_cut_x[graphdelta];
	}
	else if ( res < 0 )
	{
		return signals_cut_x[0];
	}
	else
	{
		return signals_cut_x[res];
	}

	return 	0;
}

__int64 graphdata::GetOffset()
{
	return globaloffset;
}

unsigned int graphdata::GetYOffset()
{
	return yoffset;
}

int graphdata::InitGraphData(unsigned __int64 &global_delta, 
							 unsigned __int64 &global_offset, 
							 unsigned int window_delta, 
							 unsigned int window_ratio, 
							 unsigned long signals_number, 
							 CString NewTimeType)
{
//			clear old history
    RemoveAll();
	NumberOfSignals = signals_number;
//---------------------------------------------------
	global_delta = IntervalCompare( global_delta, 6, TotalSize );
	global_offset = IntervalCompare( global_offset, 0, TotalSize - global_delta );
	window_delta = max( window_delta, window_ratio );

//	INITIALIZE NEW SETTINGS
	globaldelta	=	global_delta;
	pagelength	=	globaldelta;
	globaloffset=	global_offset;
	windowdelta	=	window_delta;
	windowratio	=	window_ratio;
	graphdelta	=	windowdelta/windowratio;
	deltax		=	windowdelta/graphdelta;
	TimeType = NewTimeType;

        signals_cut_x.SetSize(graphdelta + 1);
        signals_status.SetSize(graphdelta + 1);
	for(int i=0;i<=graphdelta;i++)
	{
		__int64 x	=	(__int64)((__int64)i*( double(globaldelta)/graphdelta)+globaloffset);

		signals_cut_x[i] = x;
        signals_status[i].ReallocateSignalsNumber(signals_number);
	}
        
        if (signals_number)
        {
            try
            {
                signal_start_pos = new DWORD[signals_number];
                memset(&signal_start_pos[0], 0, sizeof(DWORD) * signals_number);
                lastbitcoordinatesx = new xcoor[signals_number];
                lastbitcoordinatesy = new unsigned int[signals_number];
                last_signal_status.ReallocateSignalsNumber(signals_number);
                lastbitstatus.ReallocateSignalsNumber(signals_number);
				RuleBordersForSignal = new CArray< RuleBorders, RuleBorders >[signals_number];
				LastAbsoluteValue = new __int64[signals_number];
				memset( LastAbsoluteValue, 0, sizeof(__int64) * signals_number );
            }
            catch (std::bad_alloc)
            {
                RemoveAll();
                return -1;
            }
        }
			
	return 0;
}

int graphdata::PutSignalInGraph(BYTE setbit, __int64 x_pos, WORD signal_number, HighlightingRule Rule)
{
//-------------- marked line section ------------------------------
	if(	(_1stmark.optimize	==	TRUE)&&
		(_1stmark.signalID	==	signal_number)&&
		((last_signal_status.sig[signal_number]%10) != setbit))
	{
		if(_abs64(_1stmark.x_relative-x_pos)	<	_abs64(_1stmark.x_true-_1stmark.x_relative))
		{
			_1stmark.x_true	=	x_pos;
		}
	}
	if(	(_2ndmark.optimize	==	TRUE)&&
		(_2ndmark.signalID	==	signal_number)&&
		((last_signal_status.sig[signal_number]%10) != setbit))
	{
		if(_abs64(_2ndmark.x_relative-x_pos)	<	_abs64(_2ndmark.x_true-_2ndmark.x_relative))
		{
			_2ndmark.x_true	=	x_pos;
		}
	}
//-----------------------------------------------------------------

	//If x_pos is incorrect
	if(	(signals_cut_x[signal_start_pos[signal_number]] > x_pos)||
		(signals_cut_x[0]								> x_pos))
	{
		last_signal_status	.sig[signal_number]		= setbit;
		LastAbsoluteValue[signal_number] = x_pos;
		return -1;
	}
	BOOL x_pos_initiated	=	FALSE;
	RuleBorders Border;
	Border.Start = signal_start_pos[signal_number];
	for(int i=signal_start_pos[signal_number];i<=graphdelta;i++)
	{
		if(		((signals_cut_x[i] < x_pos)&&(i != graphdelta)&&(signals_cut_x[i+1] > x_pos))
			||	(signals_cut_x[i] == x_pos))
		{
			if(x_pos_initiated == FALSE)
			{
				x_pos_initiated					=	TRUE;
				signal_start_pos[signal_number]	=	i;
			}
			if(signals_status[i].sig[signal_number] < 10)
			{
				last_signal_status	.sig[signal_number]		= 
				signals_status[i]	.sig[signal_number]		=	setbit+10;
			}
			else
			{
				if((signals_status[i].sig[signal_number]%10 )	!= setbit)
				{
					last_signal_status	.sig[signal_number]	= 
					signals_status[i]	.sig[signal_number]	=	setbit+20;
				}
			}
		}
		else
		{
			if((signals_cut_x[i] < x_pos)&&
				(signals_status[i].sig[signal_number] <10)&&
				(x_pos_initiated == FALSE))
			{
				signals_status[i].sig[signal_number]=(last_signal_status.sig[signal_number]%10)+10;
			}
		}
		
		if((i	==	graphdelta)||(signals_cut_x[i+1] > x_pos))
		{
			if ( i == graphdelta )
			{
				signal_start_pos[signal_number] = i;
			}
			if ( ValueFulfilingConditionsOfRule( x_pos - LastAbsoluteValue[signal_number], Rule ) == true )
			{
				Border.End = (i == graphdelta)? i : signal_start_pos[signal_number];
				int UpperBoundOfRulesArray = RuleBordersForSignal[signal_number].GetUpperBound();
				if ( UpperBoundOfRulesArray == -1 || Border.End != RuleBordersForSignal[signal_number][UpperBoundOfRulesArray].End )
				{
					RuleBordersForSignal[signal_number].Add( Border );
				}
			}
			LastAbsoluteValue[signal_number] = x_pos;
			return 0;
		}
	}
	return 0;
}

bool graphdata::ValueFulfilingConditionsOfRule( __int64 Value, HighlightingRule Rule )
{
	switch ( Rule.TypeOfRule )
	{
	case IN_RANGE:
		{
			if ( Value == IntervalCompare( Value, Rule.Min, Rule.Max ) )
			{
				return true;
			}
			break;
		}
	case OUT_OF_RANGE:
		{
			if ( Value != IntervalCompare( Value, Rule.Min, Rule.Max ) )
			{
				return true;
			}
			break;
		}
	default:
		{
			break;
		}
	}
	return false;
}

int graphdata::FinilizeSignalInGraph( ScenarioSignals *globalsignals, __int64 LastTime )
{
	for( int signal_number=0; signal_number < globalsignals->GetNumberOfSignals(); signal_number++ )
	{
		if ( ValueFulfilingConditionsOfRule( LastTime - LastAbsoluteValue[signal_number], globalsignals->GetRule(signal_number) ) == true )
		{
			RuleBorders Border;
			Border.Start = signal_start_pos[signal_number];
			Border.End = graphdelta;
			RuleBordersForSignal[signal_number].Add( Border );
		}
		for(int pos=signal_start_pos[signal_number];pos<=graphdelta;pos++)
		{
			if(signals_status[pos].sig[signal_number] <10)
			{
				signals_status[pos].sig[signal_number]=(last_signal_status.sig[signal_number]%10)+10;
			}
		}
	}
	return 0;
}

int graphdata::GetWindowCoordinate(__int64 globalcoordinate) const
{
	int first = 0;
	int last = graphdelta;
	if ( globalcoordinate < signals_cut_x[first] )
	{
		return first*deltax;
	}
	else if (  globalcoordinate > signals_cut_x[last] )
	{
		return last*deltax;
	}
 
	while ( first < last )
	{
		int mid = ( first + last ) / 2;
		if ( globalcoordinate <= signals_cut_x[mid] )
		{
			last = mid;
		}
		else 
		{
			first = mid + 1;
		}
	}
	if ( globalcoordinate < signals_cut_x[last] )
	{
		return (last - 1)*deltax;
	} 
	else 
	{
		return last*deltax;
	}
}

/*int graphdata::GetWindowCoordinate(DWORD globalcoordinate)
{
	int		ires	=	0;
	DWORD	ddelta	=	labs(globalcoordinate -signals_cut_x[0]);
	for(int i=1;i<=graphdelta;i++)
	{
		if(labs(globalcoordinate -signals_cut_x[i])<ddelta)
		{
			ires	=	i;
			ddelta	=	labs(globalcoordinate -signals_cut_x[i]);
		}
	}
	return (deltax*ires);
}*/